home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1999 January - Disc 2 / Macworld (1999-01) (Disk 2).dmg / Serious Demos / Symbolic Composer 4.2 / Environment / Projects / Tutorial Material / Basic Tutorial / Lisp for Musicians next >
Lisp/Scheme  |  1998-10-26  |  11KB  |  435 lines

  1.  
  2.                     A Lisp Tutorial For Musicians
  3.  
  4. You may well have a book on Lisp. But, its examples are unlikely
  5. to have anything to do with music. This tutorial shows how you might
  6. begin to make sense of the primitives of Lisp in musical situations.
  7. These primitives are the building blocks of SCOM's functions. They 
  8. will be invaluable as you begin to design and customize your own 
  9. functions. 
  10.  
  11. This is an interactive tutorial. Evaluate every expression you meet.
  12. Do this by placing the cursor before the first or after the last 
  13. bracket of an expression and pressing the ENTER key. Study the 
  14. output in the Listener window.
  15.  
  16. * All SCOM's functions are created from Lisp primitives *
  17.  
  18. What is a primitive? - it's a function built into the system.
  19.  
  20. Example: (+)
  21.  
  22. (+ 3 7)
  23.  
  24. (+ 3 7 5 6)
  25.  
  26. Let's look at situations where we might use arithmetic functions:
  27.  
  28. (+ 7 3)
  29. (- 7 3)
  30. (* 7 3)
  31. (/ 7 3)
  32.  
  33. ; a list of note lengths to be added together to make a zone
  34.  
  35. (setq rhy '(24 24 48 48 96 48))
  36.  
  37. (setq zone (apply '+ rhy))
  38.  
  39. (setq zone1 (+ 24 24 48 48 96 48))
  40.  
  41. (setq zone2 (* zone 4))
  42.  
  43. (setq zone3 (/ (* zone 4) zone))
  44.  
  45. ; a practical example
  46.  
  47. (setq len '(96 48 48))
  48. (setq mat '(a c b g r t a s = d e))
  49. (setq pat '(a b c a))
  50.  
  51.  
  52. (setq zones (symbol-repeat (length pat) 
  53.                       (list (/ (* (apply '+ len)
  54.                                   (length mat)) (length pat))))
  55. )
  56.  
  57. A breakdown of this expression:
  58.  
  59. A core note-length value or the sum of a list of values (len) is 
  60. multiplied by the length of the symbol output (mat); then divided 
  61. by the length of the tonality symbol template (pat). This value is 
  62. then repeated the number of times corresponding to the length of 
  63. the tonality symbol list.
  64.  
  65. Note the primitives: length, apply, list
  66.  
  67. (length mat)
  68. (apply '+ len)
  69. (list (/ (* (apply '+ len) (length mat))(length pat))
  70.  
  71. ;_________________________________________________________________________
  72.  
  73. ; functions
  74.  
  75.  
  76. (defun dec (x)
  77.   (1- x))
  78.  
  79. (dec 5)
  80.  
  81. (defun inc (x)
  82.   (1+ x))
  83.  
  84. (inc 5)
  85.  
  86. ; shows operation of 1+ and 1- : equivalent to (- x 1) (+ x 1)
  87. ; it also shows how to make a function using the primitive defun.
  88.  
  89. Let's square some rhythmic values:
  90.  
  91. (defun sq (x)
  92.   (* x x))
  93.  
  94. (sq 5)
  95.  
  96. ; this might be used to create zones from note-lengths
  97.  
  98. (defun square-values (list-of-values)
  99.   (mapcar 'sq list-of-values))
  100.  
  101. (square-values rhy)
  102.  
  103. ; the primitive mapcar maps sq onto each value in the rhy list.
  104.  
  105. Here's another simple function using primitives mapcar and random:
  106.  
  107. (defun randomize-values (list-of-values)
  108.   (mapcar 'random list-of-values))
  109.  
  110. (setq newzones (randomize-values zones))
  111.  
  112. ; and another, this time using an SCOM function integer-to-symbol:
  113.  
  114. (defun integers-to-symbols (list-of-values)
  115.   (mapcar 'integer-to-symbol list-of-values))
  116.  
  117. (setq mat2 (integers-to-symbols '(0 2 5 3 2 6 4)))
  118.  
  119.  
  120. ;______________________________________________________________
  121.  
  122. ; list processing
  123.  
  124. (setq chords '(adf deba gib cdhi))
  125.  
  126. ; try out these expressions sequentially
  127.  
  128. (car chords)
  129. (first chords)
  130. (cdr chords) 
  131. (cadr chords)
  132. (second chords)
  133. (caddr chords)
  134. (third chords)
  135. (cddr chords)
  136. (cdddr chords)
  137. (fourth chords)
  138. (but-last chords)
  139. (last chords)
  140.  
  141. ; Lisp primitives car, cdr and associatives / derivatives
  142.  
  143. (setq progression 
  144.   (list
  145.    (car chords)
  146.    (cdr chords) 
  147.    (cadr chords)
  148.    (cddr chords)
  149.    (cdddr chords)
  150.    (but-last chords)
  151.    (last chords)))
  152.  
  153. ; this shows how the primitive list is used
  154.  
  155. (defun select-one (pattern)
  156.   (nth (random (length pattern)) pattern))  
  157.  
  158. (select-one '(1 2 3 4 5))
  159.                          
  160. ; a function to select one item from a list
  161. ; note the primitives: nth, random, length.  
  162.  
  163. (nth 3 '(1 2 3 4))
  164. (random 34)
  165. (length '(1 2 3 4))
  166.  
  167. (select-one progression) ; evaluate this several times
  168.  
  169. (setq template '(a = a = = a = a))
  170.  
  171. (setq seq1 (fill-rest template (select-one progression)) 
  172.       seq2 (fill-rest template (select-one progression))
  173.       seq3 (fill-rest template (select-one progression))
  174.       seq4 (fill-rest template (select-one progression))
  175. )
  176.  
  177. (setq phrase (append seq1 seq2 seq3 seq4))
  178.  
  179. ; the primitive append joins all the sequences together
  180.  
  181. (setq link-material (fill-template template (fourth chords)))
  182.  
  183. (setq phrase+link (cons phrase (list link-material)))
  184.  
  185. Use cons and list to create nested expressions in the zone 
  186. support function
  187.  
  188. ; ________________________________________________________________
  189.  
  190. ; predicates
  191.  
  192. (cond ((and seq1 seq2) (fourth chords))
  193.       ((and seq2 seq3) (third chords))
  194.       ((and seq3 seq4) (second chords)))
  195.  
  196. ; cond evaluates each predicate in turn until it finds one that is 'true'
  197.  
  198. ; The neural expert makes extensive use of predicates
  199. ; this example converts symbols to note lengths
  200.  
  201. (setq mat1 (gen-random 0.5 32 '(a c d a g l c c g = n m g m e d c)))
  202.  
  203. (def-neuron rhyv
  204.   (in 1 'a) '192
  205.   (in 1 'g) '96
  206.   (in 1 'm) '48
  207.   (otherwise '24))
  208.  
  209. (setq rhyb (run-neuron 'rhyv mat1))
  210.  
  211. ; to make our own symbol to length converter just with predicates
  212.  
  213. (defun symbol-to-length (symbol)
  214.    (cond ((equal symbol 'a) '(192))
  215.          ((equal symbol 'g) '(96)) 
  216.          ((equal symbol 'm) '(48))
  217.    (t '(24))))
  218.  
  219. (symbol-to-length 'a)
  220.  
  221. ; but this doesn't cope with reading a list of symbols
  222. ; here are two solutions
  223.  
  224. (setq rhyy (flatten (mapcar 'symbol-to-length mat1)))
  225.  
  226. (defun make-length (pattern)
  227.    (prog (out)
  228.       loop
  229.          (cond ((null pattern) (return out)))
  230.          (setq out
  231.             (append out
  232.                (symbol-to-length 
  233.                   (car pattern))))
  234.          (setq pattern (cdr pattern))
  235.          (go loop)))
  236.  
  237. (setq rhyx (make-length mat1))
  238.  
  239. ;________________________________________________________________________
  240.  
  241. ; recursion
  242.  
  243. The function make-length shows recursion in action.
  244.  
  245. Here is a full example to explain what's happening.
  246.  
  247. The function retro is designed to reverse the order of a list.
  248.  
  249. (defun ; function
  250.   retro ; name
  251.   (pattern) ;list of arguments
  252.   (if (null pattern)  nil ; a list of action the function is to take.
  253.       (append (last pattern) 
  254.               (retro (butlast pattern)))))
  255.  
  256. (retro '(48 50 52))
  257.  
  258.  
  259. 1. The if function calls (null pattern) - is this list empty? 
  260. ( - (null pattern) is a predicate!)
  261.  
  262. 2. The list is'nt empty - so nil (the then or consequent) is NOT 
  263. returned
  264.  
  265. 3. The else or alternative function append then takes the last of 
  266. the pattern and outputs this value (52)
  267.  
  268. 4. Recursion now begins! retro's argument pattern is shortened by 
  269. butlast function to become (48 50).
  270.  
  271. 5. This goes around again to if - it's still not an empty list so
  272. on to append and the last of (48 50) which is (50). This joins (52)
  273. as (52 50) - thanks to append which holds onto the values until the
  274. first evaluation of if is true.
  275.  
  276. 6. Recursion continues via butlast bringing it down to (48)
  277.  
  278. 7. This goes around again to if - still a list, even though it's one 
  279. atom and on to append. The function last can only return (48). This 
  280. value is then appended to the growing list (52 50 48). 
  281.  
  282. 8. Finally, recursion finishes as the list disappears!
  283.  
  284.  
  285. ; theme 
  286.  
  287. (defun retro (pattern)  
  288.   (if (null pattern)   nil  
  289.       (append (last pattern) 
  290.               (retro (butlast pattern)))))
  291.  
  292. ; a variation! 
  293.  
  294. (defun retro1 (pattern)
  295.   (cond 
  296.    ((null pattern) nil)
  297.    (t (append (retro1 (cdr pattern))
  298.               (list (car pattern))))))
  299.  
  300. (retro1 '(45 47 49))
  301.  
  302. ; here are two extensions of the earlier select-one function
  303. ; the first avoids recursion.
  304.  
  305. (setq mat3 '(a b c d))
  306.  
  307. (defun select-two (pattern)
  308.   (list 
  309.    (nth (random (length pattern)) pattern) 
  310.    (nth (random (length pattern)) pattern)))  
  311.  
  312. (select-two mat3)
  313.  
  314. ; this is, in effect, similar to gen-random, and is recursive.
  315.  
  316. (defun select-many (n pattern) 
  317.   (prog (out) 
  318.     loop 
  319.     (cond ((equal n (length out)) (return out)))
  320.     (setq out (append out (list (nth (random 
  321.                                       (length pattern)) pattern))))
  322.     (go loop)))
  323.  
  324. (select-many 32 mat3)
  325.  
  326. ; notice the predicate argument:
  327.  
  328. (cond ((equal n (length out)) (return out)))
  329.  
  330. This means - when the number chosen (n) becomes equal to the 
  331. number of recursions required to make the length of out the same 
  332. as n, out is returned. 
  333.  
  334. Notice how the variable out is made. 
  335.  
  336. (setq out (append out (list (nth etc. . .
  337.  
  338. - append collects together all the different results of looping the
  339. expression until the predicate says 'stop!, you've reached the 
  340. same number of recursions as the number you set'.
  341.  
  342. - list has to be used because each result is a single atom - a or 1 - 
  343. and needs to be (a) or (1) to be collected and joined together 
  344. by append.
  345.  
  346. ;__________________________________________________________________
  347.  
  348. Now, for some music. The following composition example uses many of 
  349. the functions and some of the material created in the tutorial.
  350. The music is a piece for keyboard and percussion. Try compiling
  351. the keyboard parts several times. You'll find that because of the
  352. select-one function the progression changes each time.
  353.  
  354. Don't press the Eval Buffer button, just outline the whole example
  355. and Eval Selection.
  356.  
  357. ; composition example - 'chordal groove'
  358.  
  359. (setq tonal1 (activate-tonality (dorian c 5) (mixolydian a& 4)))
  360. (setq tonal2 (activate-tonality (dorian c 3) (mixolydian a& 2)))
  361.  
  362. (setq chords '(adf deba gib cdhi))
  363.  
  364. (setq progression 
  365.       (list
  366.        (car chords)
  367.        (cdr chords) 
  368.        (cadr chords)
  369.        (cddr chords)
  370.        (cdddr chords)
  371.        (but-last chords)
  372.        (last chords)))
  373.  
  374. (setq template '(a = a = = a = a))
  375.  
  376. (setq seq1 (fill-rest template (select-one progression)) 
  377.       seq2 (fill-rest template (select-one progression))
  378.       seq3 (fill-rest template (select-one progression))
  379.       seq4 (fill-rest template (select-one progression)))
  380.  
  381. (setq phrase (append seq1 seq2 seq3 seq4))
  382.  
  383. (setq link-material (fill-template template (fourth chords)))
  384. (setq phrase+link (append phrase link-material))
  385.  
  386. (setq chordal (append phrase phrase+link phrase))
  387.  
  388. (setq mat3 '(a b c d))
  389. (setq mat4 (select-many 32 mat3))
  390.  
  391. (setq zonea (list (* (length phrase) 48)))
  392. (setq zoneb (list (* (length phrase+link) 48)))
  393. (setq zonec (append zonea zoneb zonea))
  394.  
  395. (def-instrument-symbol 
  396.    pianoRH  chordal
  397.    pianoLH (fill-template chordal mat4)
  398. )
  399.  
  400. (def-instrument-length
  401.    default 1/8
  402. )
  403.  
  404. (def-instrument-rhythm
  405.  
  406. cabasa '1/8 "---- ---" (z)
  407. bassdr '1/4 "-   -  -" (b)
  408. )
  409.  
  410. (def-instrument-velocity
  411.    default (select-many 32 '(112 84 74 64 74 54 54))
  412.    cabasa '(96 90 84 104 0 64 74 84)   
  413.    bassdr '(110 0 0 0 84 0 0 96)  
  414. )
  415.  
  416. (def-instrument-zone
  417.    default zonec
  418. )
  419.  
  420. (def-instrument-tonality
  421.    pianoRH  tonal1
  422.    pianoLH  tonal2
  423.    cabasa mt-32
  424.    bassdr mt-32
  425. )
  426.  
  427. (compile-instrument "ccl;output:" "groove"
  428.  pianoRH
  429.  pianoLH
  430.  bassdr
  431.  cabasa
  432. )
  433.  
  434.  
  435.